goog.provide('dkpoints.rpc.RPCService');

goog.require('dkpoints.rpc.commands.Command');

goog.require('goog.json');
goog.require('goog.net.XhrManager');
goog.require('goog.structs.Map');



/**
 * The singleton RPC service.
 * @constructor
 */
dkpoints.rpc.RPCService = function() {
  // All requests will have JSON data.
  var headers = new goog.structs.Map({
    'Content-Type': 'application/json;charset=utf-8'
  });

  /**
   * @type {goog.net.XhrManager}
   * @private
   */
  this.xhrMgr_ = new goog.net.XhrManager(
      undefined, // maxRetries (per command)
      headers
      );

  /**
   * A hash of all currently outstanding requests.  Keys are commandIDs, values
   * are the command objects themselves.
   * @private
   */
  this.runningCommands_ = {};
};


/**
 * Asynchronously execute the request encapsulated in the given Command Object.
 * @param {dkpoints.rpc.commands.Command} command The Command Object to execute.
 */
dkpoints.rpc.RPCService.prototype.execute = function(command) {
  // No caching for now.  It's late and I don't feel like writing it.
  // var callback =
  //    command.shouldCache ? this.processCacheResponse : this.processResponse;

  var commandID = command.getCommandID(),
      isPost = command.method === 'POST';
  this.runningCommands_[commandID] = command;

  // Make the call.
  this.xhrMgr_.send(
      commandID,
      command.url,
      command.method,
      isPost ? goog.json.serialize(command.data) : undefined,
      undefined,
      undefined,
      goog.bind(this.handleResponse_, this, commandID),
      command.maxRetries
  );
};


/**
 * The callback executed when a response comes in.
 *   - Determine which command this is a response for
 *   - Determine success or failure
 *   - Pass the event to the appropriate callback
 *
 * @param {string} commandID The ID of the command object.
 * @param {goog.net.XhrManager.Event} event the XHR Complete event.
 * @private
 */
dkpoints.rpc.RPCService.prototype.handleResponse_ = function(commandID, event) {
  var xhr = event.target,
      command = this.runningCommands_[commandID];

  if (command) {
    if (xhr.isSuccess()) {
      command.onSuccess(event);
    }
    else {
      command.onFailure(event);
    }
    delete this.runningCommands_[commandID];
  }
};
